package cn.changeforyou.demo.netty.client;

import cn.changeforyou.demo.netty.common.SSLContextFactory;
import cn.changeforyou.demo.netty.common.YbkjTcpDataDecoder;
import cn.changeforyou.demo.netty.common.YbkjTcpDataEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.timeout.IdleStateHandler;
import java.net.InetSocketAddress;
import javax.net.ssl.SSLEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author zhyu
 * @date 2020/9/14 16:16
 */

public class Client {

	static Logger log = LoggerFactory.getLogger(ClientHandler.class);
	private boolean enableSsl;

	public void setEnableSsl(boolean enableSsl) {
		this.enableSsl = enableSsl;
	}

	/**
	 * 当前重接次数
	 */
	private int reconnectTimes = 1;

	public Client(String host, int port) {
		remoteAddress = new InetSocketAddress(host, port);
	}

	public static void main(String[] args) {
		//todo 初始化 代码
//		Scanner scanner = new Scanner(System.in);
//		log.info("请指定用户凭证");
//		token = scanner.nextLine();
//		scanner.close();
        token = "haha";
//		Client client = new Client("192.168.110.204", 443);
		Client client = new Client("47.108.175.1", 443);
		client.setEnableSsl(true);
		try {
			client.connect();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static String token;
	private Bootstrap bootstrap;
	InetSocketAddress remoteAddress;

	public void connect() {
		EventLoopGroup group = new NioEventLoopGroup();
		try {
            SSLEngine sslEngine = new SSLContextFactory().getClientSslContext().createSSLEngine();
            sslEngine.setUseClientMode(true);
            final SslHandler sslHandler = new SslHandler(sslEngine);
			bootstrap = new Bootstrap();
			bootstrap.group(group).channel(NioSocketChannel.class).remoteAddress(remoteAddress).option(ChannelOption.SO_KEEPALIVE, true)
				.handler(new ChannelInitializer<SocketChannel>() {
					@Override
					protected void initChannel(SocketChannel ch) throws Exception {
						ChannelPipeline pipeline = ch.pipeline();
						pipeline.addLast(new IdleStateHandler(0, 20, 0));
						if(enableSsl) {
							pipeline.addLast(sslHandler);
						}
						pipeline.addLast(new YbkjTcpDataDecoder());
						pipeline.addLast(new YbkjTcpDataEncoder());
						pipeline.addLast(new ClientHandler(token));
						pipeline.addLast(new HeartbeatHandler(token));
					}
				});
			ChannelFuture f = bootstrap.connect(remoteAddress)
				                  .sync();
			f.channel().closeFuture().sync();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			//          group.shutdownGracefully();  //这里不再是优雅关闭了
			//设置最大重连次数，防止服务端正常关闭导致的空循环
			if (reconnectTimes <= 10) {
				reConnectServer();
			} else {
				log.error("重连次数已经达到上限, 关闭client");
//                group.shutdownGracefully(10L, 10L, TimeUnit.SECONDS);
				group.shutdownGracefully();
			}
		}
	}

	/**
	 * 断线重连
	 */
	private void reConnectServer() {
		try {
			Thread.sleep(5000);
			log.error("客户端进行断线重连[{}]", reconnectTimes);
			reconnectTimes++;
			connect();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
